package com.woohua.thread.lock;

/***
 * @title DeadLockDemo
 * @description: 死锁
 *          一、死锁条件
 *             1、互斥：共享资源 X 和 Y 只能被一个资源占用
 *             2、占有且等待：线程 T1 已经取得共享资源 X， 在资源等待的时候，不释放共享资源 X
 *             3、不可抢占： 其他线程不能强行抢占 线程 T1 占有的资源。应为不可抢占，所以要等待
 *             4、循环等待：线程 T1 等待线程 T2 占有的资源，线程 T2 等待线程 T1 占有的资源
 *         这四个条件同时满足时，才会发生死锁，因此避免死锁只要打破其中一个条件即可。
 *
 *         二、避免死锁的方法
 *            1、对于互斥这个条件无法破坏，因为使用锁为的就是互斥
 *            2、对于占有且等待：可以同时获取要使用的多个资源锁 X 和 Y，这样就不会存取得了 X 还要等待 Y。
 *              这种方式只需要获取的资源锁较少的情况下使用，如果要获取的资源锁很多（例如10个），就不太可行。
 *            3、对于不可抢占：可以获取了部分资源，再进一步获取其他资源时，如果获取不到，把已经获取的资源一起释放掉。
 *              此时意味着操作不能按预期处理，需要考虑异常如何处理，例如是否需要重试。
 *            4、对于循环等待，可以将需要获取的锁资源排序，按照顺序获取，这样就不会多个线程交叉获取相同的资源导致死锁，
 *              而是在获取相同的资源时就等待，直到它释放。
 *
 *          对于极易发生死锁的场景，处理如下：
 *             1、获取锁时带上超时时间，获取不到就放弃，这样能最简单的避免死锁，者意味着不能使用 synchronized 关键字来获得锁资源。
 *             2、对于已经获取到的锁资源，增加主动释放机制。
 *             3、放弃锁资源时进行异常处理，如重试。
 *             4、需要获取的锁资源顺序处理，虽然前面几点可以一定程度避免死锁，但不排序的结果就是首次处理失败，
 *               重试时还能再次失败，虽然没有发生死锁，但同一笔业务重试了N次可能也没有成功，导致无谓占用资源。
 * @author woo hua
 * @version 1.0.0
 * @create 2023/3/10 14:44
 **/
public class DeadLockDemo {

    public static void main(String[] args) {
        // 创建两个用于加锁的对象
        final Object lockX = new Object();
        final Object lockY = new Object();

        System.out.println("lockX " + lockX);
        System.out.println("lockY " + lockY);

        Thread tX = new Thread(new Worker(lockX, lockY), "tX");
        // 交换锁的顺序，模拟死锁
        Thread tY = new Thread(new Worker(lockY, lockX), "tY");

        tX.start();
        tY.start();
    }
}
